module windump.plugins.htmlinput.ie.html;

import std.c.windows.windows;

import windump.utf;
import windump.combase;
import windump.plugins.htmlinput.ie.shdocvw;
import windump.plugins.htmlinput.ie.mshtml;

class HtmlException : Exception
{
	public this(string msg)
	{
		super(msg);
	}
}

private void throwWhenFailed(HRESULT hr)
{
	if(hr != S_OK)
		throw new HtmlException("HtmlException  :" ~ __FILE__);
}

class WebBrowser
{
	private IWebBrowser m_browser;

	invariant
	{
		assert(m_browser !is null);
	}

	public this(IWebBrowser browser)
	{
		m_browser = browser;
	}

	public ~this()
	{
		tryRelease(m_browser);
	}

	public string url()
	{
		wchar* str;
		HRESULT hr = m_browser.get_LocationURL(str);
		if(hr != S_OK)
			throw new HtmlException("Failed to get url");
		return bstrToUtf8(str);
	}

	public HtmlDocument document()
	{
		IDispatch disp;
		HRESULT hr = m_browser.get_Document(disp);
		if(hr != S_OK)
			throw new HtmlException("failed to get document");
		auto doc = new HtmlDocument(disp);
		return doc;
	}

}


class HtmlDocument
{
	private IHTMLDocument2 m_doc;

	private this(IDispatch disp)
	{
		m_doc = com_cast!(IHTMLDocument2)(disp);
		if(m_doc is null)
			throw new HtmlException("Failed to cast IDispatch to IHTMLDocument2");
	}

	public ~this()
	{
		tryRelease(m_doc);
	}

	HtmlElement getElementByID(string id)
	{
		IHTMLDocument3 doc = com_cast!(IHTMLDocument3)(m_doc);
		if(doc is null)
			throw new HtmlException("Failed to cast doc2 to doc3");
		IHTMLElement iele;
		doc.getElementById(toUtf16z(id), iele);
		auto ele = new HtmlElement(iele);
		return ele;
	}

	public HtmlElementCollection all()
	{
		IHTMLElementCollection ec;
		HRESULT hr = m_doc.get_all(ec);
		if(hr != S_OK)
			throw new HtmlException("Failed to get all element from document");
		auto ret = new HtmlElementCollection(ec);
		return ret;
	}

}

class HtmlElement
{
	private IHTMLElement m_ele;

	invariant
	{
		assert(m_ele !is null);
	}

	public this(IHTMLElement ele)
	{
		m_ele = ele;
	}

	public this(IDispatch disp)
	{
		IHTMLElement ele = com_cast!(IHTMLElement)(disp);
		if(ele is null)
			throw new HtmlException("Failed to cast IDispatch to IHTMLElement");
		this(ele);
	}

	public ~this()
	{
		tryRelease(m_ele);
	}

	public string outerHtml()
	{
		wchar* str;
		HRESULT hr = m_ele.get_outerHTML(str);		
		if(hr != S_OK)
			throw new HtmlException("failed to get outer html");
		return bstrToUtf8(str);
	}

	void outerHtml(string str)
	{
		HRESULT hr = m_ele.set_outerHTML(toUtf16z(str));
		if(hr != S_OK)
			throw new HtmlException("failed to set outerhtml");
	}

}

class HtmlElementCollection
{	
	private IHTMLElementCollection m_ec;

	invariant
	{
		assert(m_ec !is null);
	}

	public this(IHTMLElementCollection ec)
	{
		m_ec = ec;
	}

	public ~this()
	{
		tryRelease(m_ec);
	}

	public IDispatch getItem(string name)
	{
		IDispatch disp;
		HRESULT hr = m_ec.item(VARIANT(name), VARIANT(0), disp);
		if(hr != S_OK)
			throw new HtmlException("Failed to item");
		return disp;
	}
	
	public IDispatch getItem(int index)
	{
		IDispatch disp;
		throwWhenFailed(m_ec.item(VARIANT(index), VARIANT(0), disp));
		return disp;
	}

	public int length()
	{
		int n;
		m_ec.get_length(n);
		return n;
	}

	public void length(int n)
	{
		throwWhenFailed(m_ec.set_length(n));
	}
}

class HtmlInputTextElement
{
	private IHTMLInputTextElement m_ite;

	invariant
	{
		assert( m_ite !is null);
	}

	public this(IHTMLInputTextElement ite)
	{
		m_ite = ite;
	}

	public this(IDispatch disp)
	{
		IHTMLInputTextElement ite = com_cast!(IHTMLInputTextElement)(disp);
		if(ite is null)
			throw new HtmlException("Failed to cast IDispatch to IHTMLInputTextElement");
		this(ite);
	}

	public string type()
	{
		wchar* t;
		throwWhenFailed(m_ite.get_type(t));
		return bstrToUtf8(t);
	}

	public string value()
	{
		wchar* v;
		throwWhenFailed(m_ite.get_value(v));
		return bstrToUtf8(v);
	}
	
	public string name()
	{
		wchar* n;
		throwWhenFailed(m_ite.get_name(n));
		return bstrToUtf8(n);
	}

}

